package hk.edu.polyu.comp446.group5;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;

import org.jfree.ui.RefineryUtilities;

public class FinancialFunctionCaller {
	String stockCode1;
	String stockCode2;

	// Initial Variables - Stock
	BigDecimal fcmean; // Mean
	BigDecimal fcvariance; // Variance
	BigDecimal fcsd; // Standard Deviation
	BigDecimal fcskew; // Skewness
	BigDecimal fckurt; // Kurtosis
	BigDecimal fcvar; // Value At Risk
	BigDecimal fcsharpe; // Sharpe Ratio

	// Initial Variables - Portfolio
	BigDecimal pcovariance;
	BigDecimal pcorrelation;
	BigDecimal pmean;
	BigDecimal pvariance; // Variance
	BigDecimal psd; // Standard Deviation
	BigDecimal pvar; // Value At Risk
	BigDecimal psharpe; // Sharpe Ratio
	BigDecimal pvarwith10000; // Sharpe Ratio with $10000 and 0.10 Quantile
	BigDecimal pgminA;
	BigDecimal pgminB;
	BigDecimal ptanA;
	BigDecimal ptanB;
	BigDecimal peffRiskA;
	BigDecimal peffRiskB;
	BigDecimal peffRisk;
	BigDecimal peffReturnA;
	BigDecimal peffReturnB;
	BigDecimal peffReturn;

	Boolean portfolio = false;
	double stockAPercentage;
	double stockBPercentage;
	double initInvest = 1.0;
	double quantile = 0.05;
	double expectedReturn = 0.008;
	double expectedRisk = 0.06;

	// For Testing Use ONLY!!!
	//public static void main(String[] args) {
	//	FinancialFunctionCaller test = new FinancialFunctionCaller("veiex", "vfinx", 0.4, 0.6);
	//	test.run();
	//}

	public FinancialFunctionCaller(String stockname) {
		this.stockCode1 = stockname;
	}

	public FinancialFunctionCaller(String stockname1, String stockname2, double stockAPercentage, double stockBPercentage) {
		this.stockCode1 = stockname1;
		this.stockCode2 = stockname2;
		this.stockCode2 = this.stockCode2.toLowerCase();
		this.portfolio = true;
		this.stockAPercentage = stockAPercentage;
		this.stockBPercentage = stockBPercentage;
	}

	public FinancialFunctionCaller(String stockname1, String stockname2, double stockAPercentage, double stockBPercentage, double initInvest, double quantile) {
		this.stockCode1 = stockname1;
		this.stockCode2 = stockname2;
		this.stockCode2 = this.stockCode2.toLowerCase();
		this.portfolio = true;
		this.stockAPercentage = stockAPercentage;
		this.stockBPercentage = stockBPercentage;

		this.initInvest = initInvest;
		this.quantile = quantile;
	}

	public FinancialFunctionCaller(String stockname1, String stockname2, double stockAPercentage, double stockBPercentage, double initInvest, double quantile, double expectedReturn, double expectedRisk) {
		this.stockCode1 = stockname1;
		this.stockCode2 = stockname2;
		this.stockCode2 = this.stockCode2.toLowerCase();
		this.portfolio = true;
		this.stockAPercentage = stockAPercentage;
		this.stockBPercentage = stockBPercentage;

		this.initInvest = initInvest;
		this.quantile = quantile;

		this.expectedReturn = expectedReturn;
		this.expectedRisk = expectedRisk;
	}

	public void run() {
		try {
			this.stockCode1.toLowerCase();
			FileInputStream fstream = new FileInputStream(this.stockCode1 + ".txt");
			DataInputStream in = new DataInputStream(fstream);
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String strLine;
			// For Stock 1
			String allData[] = new String[61];
			double stockPriceOnly[] = new double[61];
			int i = 0;
			while ((strLine = br.readLine()) != null) {
				String[] tmp = strLine.split(","); // Split by "Comma"
				stockPriceOnly[i] = Double.parseDouble(tmp[2]);
				allData[i] = strLine;
				i++;
			}
			// For Stock 2
			String allData2[] = new String[61];
			double stockPriceOnly2[] = new double[61];
			if (this.portfolio) {
				this.stockCode2.toLowerCase();
				FileInputStream fstream2 = new FileInputStream(this.stockCode2 + ".txt");
				DataInputStream in2 = new DataInputStream(fstream2);
				BufferedReader br2 = new BufferedReader(new InputStreamReader(in2));
				String strLine2;
				int k = 0;
				while ((strLine2 = br2.readLine()) != null) {
					String[] tmp2 = strLine2.split(",");
					stockPriceOnly2[k] = Double.parseDouble(tmp2[2]);
					allData2[k] = strLine2;
					k++;
				}
			}
			try {
				// Call Financial Core Function
				FinancialCore financeCore = new FinancialCore("CCReturn");
				this.fcmean = new BigDecimal(financeCore.Mean(stockPriceOnly).getMean()).setScale(6, BigDecimal.ROUND_HALF_UP);
				this.fcvariance = new BigDecimal(financeCore.Variance(stockPriceOnly).getVariance()).setScale(6, BigDecimal.ROUND_HALF_UP);
				this.fcsd = new BigDecimal(financeCore.StdDev(stockPriceOnly).getStdDeviation()).setScale(6, BigDecimal.ROUND_HALF_UP);
				this.fcskew = new BigDecimal(financeCore.Skewness(stockPriceOnly).getSkew()).setScale(6, BigDecimal.ROUND_HALF_UP);
				this.fckurt = new BigDecimal(financeCore.Kurtosis(stockPriceOnly).getKurtosis()).setScale(6, BigDecimal.ROUND_HALF_UP);
				this.fcvar = new BigDecimal(financeCore.ValueAtRisk(stockPriceOnly).getValueAtRisk()).setScale(6, BigDecimal.ROUND_HALF_UP);
				this.fcsharpe = new BigDecimal(financeCore.SharpeRatio(stockPriceOnly).getSharpeRatio()).setScale(6, BigDecimal.ROUND_HALF_UP);

				// Portfolio
				if (this.portfolio) {
					FinancialCore financePortfolio = new FinancialCore("SimpleReturn");
					this.pcovariance = new BigDecimal(financePortfolio.Covariance(stockPriceOnly, stockPriceOnly2).getCovariance()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.pcorrelation = new BigDecimal(financePortfolio.Correlation(stockPriceOnly, stockPriceOnly2).getCorrelation()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.pmean = new BigDecimal(financePortfolio.Mean(stockPriceOnly, stockPriceOnly2, stockAPercentage, stockBPercentage).getMean()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.pvariance = new BigDecimal(financePortfolio.Variance(stockPriceOnly, stockPriceOnly2, stockAPercentage, stockBPercentage).getVariance()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.psd = new BigDecimal(financePortfolio.StdDev(stockPriceOnly, stockPriceOnly2, stockAPercentage, stockBPercentage).getStdDeviation()).setScale(6, BigDecimal.ROUND_HALF_UP);
					//this.pvar = new BigDecimal(financePortfolio.ValueAtRisk(stockPriceOnly, stockPriceOnly2, stockAPercentage, stockBPercentage).getValueAtRisk()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.pvar = new BigDecimal(financePortfolio.ValueAtRisk(stockPriceOnly, stockPriceOnly2, stockAPercentage, stockBPercentage, initInvest, quantile).getValueAtRisk()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.psharpe = new BigDecimal(financePortfolio.SharpeRatio(stockPriceOnly, stockPriceOnly2, stockAPercentage, stockBPercentage).getSharpeRatio()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.pgminA = new BigDecimal(financePortfolio.GlobalMinVarPortfolioA(stockPriceOnly, stockPriceOnly2).getGlobalMin()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.pgminB = new BigDecimal(financePortfolio.GlobalMinVarPortfolioB(stockPriceOnly, stockPriceOnly2).getGlobalMin()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.ptanA = new BigDecimal(financePortfolio.TangencyPortfolioA(stockPriceOnly, stockPriceOnly2).getTangency()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.ptanB = new BigDecimal(financePortfolio.TangencyPortfolioB(stockPriceOnly, stockPriceOnly2).getTangency()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.peffRiskA = new BigDecimal(financePortfolio.EfficientPortfoliosRiskA(stockPriceOnly, stockPriceOnly2, expectedReturn).getEfficientPortfolio()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.peffRiskB = new BigDecimal(financePortfolio.EfficientPortfoliosRiskB(stockPriceOnly, stockPriceOnly2, expectedReturn).getEfficientPortfolio()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.peffRisk = new BigDecimal(financePortfolio.EfficientPortfoliosRisk(stockPriceOnly, stockPriceOnly2, expectedReturn).getEfficientPortfolioRisk()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.peffReturnA = new BigDecimal(financePortfolio.EfficientPortfoliosReturnA(stockPriceOnly, stockPriceOnly2, expectedRisk).getEfficientPortfolio()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.peffReturnB = new BigDecimal(financePortfolio.EfficientPortfoliosReturnB(stockPriceOnly, stockPriceOnly2, expectedRisk).getEfficientPortfolio()).setScale(6, BigDecimal.ROUND_HALF_UP);
					this.peffReturn = new BigDecimal(financePortfolio.EfficientPortfoliosReturn(stockPriceOnly, stockPriceOnly2, expectedRisk).getEfficientPortfolioReturn()).setScale(6, BigDecimal.ROUND_HALF_UP);
				}
				// DEBUG USE ONLY - Stocks
				System.out.println("Mean: " + fcmean);
				System.out.println("Variance: " + fcvariance);
				System.out.println("SDev: " + fcsd);
				System.out.println("Skew: " + fcskew);
				System.out.println("Kurtosis: " + fckurt);
				System.out.println("VaR: " + fcvar);
				System.out.println("Sharpe Ratio: " + fcsharpe);

				// DEBUG USE ONLY - Portfolio
				System.out.println("Covariance: " + pcovariance);
				System.out.println("Correlation: " + pcorrelation);
				System.out.println("Mean: " + pmean);
				System.out.println("Variance: " + pvariance);
				System.out.println("SDev: " + psd);
				System.out.println("VaR: " + pvar);
				System.out.println("VaR with $10000 and 0.10 Quantile: " + pvarwith10000);
				System.out.println("Sharpe Ratio: " + psharpe);
				System.out.println("Global Min Asset A: " + pgminA);
				System.out.println("Global Min Asset B: " + pgminB);
				System.out.println("Tangency A: " + ptanA);
				System.out.println("Tangency B: " + ptanB);
				System.out.println("Efficient Risk A: " + peffRiskA);
				System.out.println("Efficient Risk B: " + peffRiskB);
				System.out.println("Efficient Risk: " + peffRisk);
				System.out.println("Efficient Return A: " + peffReturnA);
				System.out.println("Efficient Return B: " + peffReturnB);
				System.out.println("Efficient Return: " + peffReturn);
				// System.out.println("Get 0.01 Quantiles: " + NormSInv.getInvCDF(0.01, false)); // Get 0.01 Quantiles
				// System.out.println("Get 0.0025 Quantiles: " + NormSInv.getInvCDF(0.025, false)); // Get 0.025 Quantiles
				// System.out.println("Get 0.05 Quantiles: " + NormSInv.getInvCDF(0.05, false)); // Get 0.05 Quantiles
				// System.out.println(FinancialCore.NormInv(0.05, financeCore.Mean(stockPriceOnly).getMean(), financeCore.StdDev(stockPriceOnly).getStdDeviation()));
				// System.out.println(FinancialCore.NormInv(0.05, 0.05, 0.1)); // Quantiles
				// System.out.println(FinancialCore.NormInv(0.05, 0.05, 0.1) * 10000); // Simple Returns - Value at Risk
				// System.out.println((Math.exp(FinancialCore.NormInv(0.05, 0.05, 0.1)) - 1) * 10000); // Continuously Compounded Returns - Value at Risk

			} catch (Throwable e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			in.close();
		} catch (Exception e) { // Catch exception if any
			System.err.println("Error: " + e.getMessage());
		}
	}
}